/**
 * Copyright (C) 2012 The SkyTvOS Project
 *
 * Version     Date           Author
 * ─────────────────────────────────────
 *           2016-4-16         yellowlgx
 *
 */

package com.skyworth.ui.listview;

import java.lang.ref.WeakReference;
import java.util.LinkedList;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.Adapter;
import android.widget.AdapterView;

import com.skyworth.ui.customview.SlideFocusView;
import com.skyworth.ui.listview.MetroAdapter.ObserverListener;

/**
 * @ClassName MetroHListView
 * @Description 通用型横向列表式Layout，提供竖向平滑滚动<br/>
 *              支持单列(即类似ListView)，多列(类似GridView)，其中子Item需要外部自己控制大小<br/>
 *              支持数据更新，数据由MetroAdapter提供,其中不支持上下左右间隔，需要间隔的需要在自己的Item中自行添加Padding<br/>
 *              注意：添加了Padding后，子Item的大小需要计算Padding，这个涉及到具体哪个Item横向是触发滚动<br/>
 *              由于触发滚动是根据当前选中项，加上一个Item的宽度，判断是否超出底边来触发的，需要注意
 * @author yellowlgx
 * @date 2016-4-16
 */
public class MetroHListView extends AdapterView<Adapter> implements ObserverListener,
        OnKeyListener, OnClickListener
{
    // 新添加的所有子视图在当前最当前最后一个子视图后添加的布局模型
    private static final int LAYOUT_MODE_BELOW = 0;
    // 与LAYOUT_MODE_BELOW相反方向添加的布局模型
    private static final int LAYOUT_MODE_ABOVE = 1;

    private static final int SCROLL_STATE = 110;

    private static final int ON_SCROLL_END = 111;

    private Adapter mAdapter;
    // 当前显示最后一个Item在Adapter中位置
    private int mLastItemPosition;
    // 当前显示第一个Item在Adapter中位置
    private int mFirstItemPosition;
    // 当前选中位置
    private int curSelectPosition;

    // 当前顶部第一个item
    private int mListLeft;
    // 当前第一个显示的item与底部第一个item的顶部偏移量
    private int mListLeftOffset;
    // onkey上下键时进行记录
    private int mListLeftStart;

    // View复用当前仅支持一种类型Item视图复用
    // 想更多了解ListView视图如何复用可以看AbsListView内部类RecycleBin
    private final LinkedList<View> mCachedItemViews = new LinkedList<View>();
    private RecycleBin mRecycleBin;

    /**
     * @Fields scrollState 滚动状态，true表示还在滚动，false表示滚动结束
     */
    private boolean scrollState = false;

    /**
     * @Fields SCROLL_DURING 滚动动画执行时间
     */
    private int SCROLL_DURING = 100;

    private int duration = 100;

    /**
     * @Fields onKeyTime按键时间，用于快速按上下键时更新滚动时间
     */
    private long onKeyTime = 0;

    /**
     * @Fields key 当前按键键值
     */
    private int key = 0;

    // /**
    // * @Fields clomusNum GridView显示列数
    // */
    // private int colmusNum = 1;

    /**
     * @Fields mListener 提供外部当前选中和未选中Item的接口监听
     */
    private OnHItemSelectedListener mListener;

    /**
     * @Fields scrollListener 当前滚动状态接口监听，目前只提供滚动结束回调
     */
    private OnHScrollStateListener scrollListener;

    /**
     * @Fields borderItemOnKeyListener 当前边界按键监听
     */
    private OnHItemOnKeyListener itemOnKeyListener;

    private MyHandler mHandler;

    /**
     * @Fields mSlideFocusView 父控件对象，用于控制焦点逻辑
     */
    private SlideFocusView mSlideFocusView;

    // /**
    // * @Fields scrollBarBgView 滚动条背景
    // * @Fields scrollBar 滚动条
    // */
    // private MetroListViewScrollBar scrollBarView;

    /**
     * @Fields mItemClickListener 子Item点击事件回调
     */
    private OnItemClickListener mItemClickListener;

    // /**
    // * @Fields mBarOnKeyListener 滚动条按键监听
    // */
    // private OnScrollBarOnKeyListener mBarOnKeyListener;

    // /**
    // * @Fields isOnePage 列表是否超出一屏的标志位<br/>
    // * true为大于一屏，false反之
    // */
    // private boolean isOnePage = false;

    /**
     * @Fields isOnKeyUp 按键事件是否是放开按键
     */
    private boolean isOnKeyUp = false;

    // /**
    // * @Fields scrollBarFocus 当前滚动条可落焦状态
    // */
    // private boolean scrollBarFocus = false;

    /**
     * @Fields mAttached 当前View的销毁状态
     */
    private boolean mAttached = false;

    /**
     * @ClassName OnItemSelectedListener
     * @Description 子Item选中和未选中接口
     */
    public interface OnHItemSelectedListener
    {
        public void onHItemSelected(MetroHListView parent, View selectView, int selectPosition);

        public void onHItemUnSelected(MetroHListView parent, View unSelectView);
    }

    /**
     * @ClassName OnScrollStateListener
     * @Description 滚动状态接口，提供滚动结束后当前现实中第一个位置和最后一个位置<br/>
     *              用于外部需要更新数据时，当前显示的是第几个数据
     */
    public interface OnHScrollStateListener
    {
        /**
         * @Description 滚动结束是的回调<br/>
         * @param parent
         *            当前ListView
         * @param firstPostion
         *            当前显示中的第一个位置，也就是数据List中的具体位置
         * @param endPosition
         *            当前现显示中的最后一个位置，也就是数据使用到的最后位置 void
         */
        public void onHScrollEnd(MetroHListView parent, int firstPostion, int endPosition);
    }

    /**
     * @ClassName OnBorderItemOnKeyListener
     * @Description Item上按键回调
     * @author yellowlgx
     */
    public interface OnHItemOnKeyListener
    {
        /**
         * @Description 边界Item按键回调，主要处理边界上下左右按键<br/>
         * @param view
         * @param keyCode
         * @param position
         * @return boolean
         */
        public boolean onHBorderItemOnKeyEvent(View view, int keyCode, int position);

        /**
         * @Description Item上按键回调，过滤了本身需要被处理的上下左右，其余按键均会回调<br/>
         * @param view
         * @param keyCode
         * @param position
         * @return boolean
         */
        public boolean onHItemOnKeyEvent(View view, int keyCode, int position);
    }

    // /**
    // * @ClassName OnScrollBarOnKeyListener
    // * @Description 主要用于滚动条按键回调
    // */
    // public interface OnScrollBarOnKeyListener
    // {
    // public boolean onScrollBarOnKey(View view, int keyCode);
    // }

    // 构造函数
    public MetroHListView(Context context)
    {
        super(context);
        this.setFocusable(false);
        mHandler = new MyHandler(this);
        mRecycleBin = new RecycleBin();
    }

    /**
     * @Description 设置父控件对象，主要用于处理焦点逻辑(换图或者是改变位置大小等)
     * @param focusView
     *            void
     * @date 2016-1-11
     */
    public void setSlidFocusView(SlideFocusView focusView)
    {
        mSlideFocusView = focusView;
    }

    /**
     * @Description 选中未选中监听注册
     * @param listener
     *            void
     */
    public void setOnHItemSelectedListener(OnHItemSelectedListener listener)
    {
        mListener = listener;
    }

    /**
     * @Description 滚动状态监听注册
     * @param listener
     *            void
     */
    public void setOnHScrollStateListener(OnHScrollStateListener listener)
    {
        scrollListener = listener;
    }

    /**
     * @Description 注册边界按键监听<br/>
     * @param listener
     *            void
     */
    public void setOnHItemOnKeyListener(OnHItemOnKeyListener listener)
    {
        itemOnKeyListener = listener;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * android.widget.AdapterView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener
     * )
     */
    public void setOnHItemClickListener(OnItemClickListener listener)
    {
        mItemClickListener = listener;
    }

    // public void setOnScrollBarOnKeyListener(OnScrollBarOnKeyListener listener)
    // {
    // mBarOnKeyListener = listener;
    // }

    @Override
    protected void onAttachedToWindow()
    {
        super.onAttachedToWindow();
        mAttached = true;
    }

    // 销毁View的时候系统方法，此处用于销毁adapter中的观察者，以防内存泄露
    @Override
    protected void onDetachedFromWindow()
    {
        if (mAdapter != null)
            ((MetroAdapter<?>) mAdapter).registObserver(null);
        mAttached = false;
        super.onDetachedFromWindow();
    }

    @Override
    public Adapter getAdapter()
    {
        return mAdapter;
    }

    @Override
    public void setAdapter(Adapter adapter)
    {
        this.mAdapter = adapter;
        ((MetroAdapter<?>) mAdapter).registObserver(this);
        removeAllViewsInLayout();
        mListLeft = 0;
        mListLeftOffset = 0;
        mListLeftStart = 0;
        mFirstItemPosition = 0;
        mLastItemPosition = -1;
        mCachedItemViews.clear();
        mRecycleBin.clear();

        mRecycleBin.setViewTypeCount(mAdapter.getViewTypeCount());
        // if (scrollBarView != null)
        // {
        // scrollBarView.setScrollBarToPosition(0);
        // scrollBarView.setVisibility(View.GONE);
        // }
        requestLayout();

        // this.post(new Runnable()
        // {
        // @Override
        // public void run()
        // {
        // if (getChildAt(0) != null)
        // {
        // getChildAt(0).post(new Runnable()
        // {
        // @Override
        // public void run()
        // {
        // if (scrollBarView != null && getChildAt(0) != null)
        // {
        // int temp = MetroHListView.this.getWidth()
        // / getChildAt(0).getWidth();
        //
        // int gridTotalHeight = getCol(mAdapter.getCount())
        // * getChildAt(0).getHeight()
        // - (temp * getChildAt(0).getHeight());
        // if (gridTotalHeight > 0)
        // {
        // if (scrollBarView.getVisibility() != View.VISIBLE)
        // scrollBarView.setVisibility(View.VISIBLE);
        // isOnePage = false;
        // } else if (gridTotalHeight <= 0)
        // {
        // if (scrollBarView.getVisibility() == View.VISIBLE)
        // scrollBarView.setVisibility(View.GONE);
        // isOnePage = true;
        // }
        // }
        // }
        // });
        // }
        // }
        // });
    }

    public void setAdapter(Adapter adapter, final int startPosition)
    {
        this.mAdapter = adapter;
        ((MetroAdapter<?>) mAdapter).registObserver(this);
        removeAllViewsInLayout();
        mListLeft = 0;
        mListLeftOffset = 0;
        mListLeftStart = 0;
        // final int mode = startPosition % getColmusNum();
        mFirstItemPosition = startPosition;
        mLastItemPosition = startPosition - 1;
        mCachedItemViews.clear();
        // if (scrollBarView != null)
        // scrollBarView.setVisibility(View.GONE);
        mRecycleBin.clear();

        mRecycleBin.setViewTypeCount(mAdapter.getViewTypeCount());
        requestLayout();

        // this.post(new Runnable()
        // {
        // @Override
        // public void run()
        // {
        // if (getChildAt(0) != null)
        // {
        // getChildAt(0).post(new Runnable()
        // {
        // @Override
        // public void run()
        // {
        // if (scrollBarView != null && getChildAt(0) != null)
        // {
        // scrollBarView.getScrollBarView().post(new Runnable()
        // {
        // @Override
        // public void run()
        // {
        // int itemH = getChildAt(0).getHeight();
        // int col = startPosition / getColmusNum();
        // int value = col * itemH;
        // int scrollHeight = scrollBarView.getScrollBarHeight()
        // - scrollBarView.getScrollBarView().getHeight();
        //
        // int temp = MetroHListView.this.getHeight()
        // / getChildAt(0).getHeight();
        //
        // int gridTotalHeight = getCol(mAdapter.getCount())
        // * getChildAt(0).getHeight()
        // - (temp * getChildAt(0).getHeight());
        // int scrollPostion = 0;
        // if (gridTotalHeight > 0)
        // {
        // if (scrollBarView.getVisibility() != View.VISIBLE)
        // scrollBarView.setVisibility(View.VISIBLE);
        // scrollPostion = (int) ((float) (value * scrollHeight)
        // / gridTotalHeight + 0.5f);
        // scrollBarView.setScrollBarToPosition(scrollPostion);
        // isOnePage = false;
        // } else if (gridTotalHeight <= 0)
        // {
        // if (scrollBarView.getVisibility() == View.VISIBLE)
        // scrollBarView.setVisibility(View.GONE);
        // isOnePage = true;
        // }
        // }
        // });
        // }
        // }
        // });
        // }
        // }
        // });
    }

    @Override
    public void onChanaged()
    {
        if (mAdapter != null)
        {
            for (int i = 0; i < this.getChildCount(); i++)
            {
                int position = this.getChildAt(i).getId();
                mAdapter.getView(position, this.getChildAt(i), this);
                ((MetroListItem) getChildAt(i)).refreshView();
            }
            invalidate();
        }
    }

    @Override
    public void onChanagedTotal()
    {
        if (mAdapter != null)
        {
            // scrollBarFocus = scrollBarView.getScrollBarFocusBle();
            // if (mSlideFocusView != null && scrollBarView != null && !scrollBarView.hasFocused())
            // {
            // mSlideFocusView.getFocusView().setVisibility(View.INVISIBLE);
            // scrollBarView.setVisibility(View.GONE);
            // scrollBarView.getScrollBarView().setFocusable(false);
            // this.requestFocus();
            // }

            mListLeft = 0;
            mListLeftOffset = 0;
            mListLeftStart = 0;
            mFirstItemPosition = getFirstPosition();
            mLastItemPosition = getFirstPosition() - 1;
            mCachedItemViews.clear();
            mRecycleBin.clear();
            removeAllViewsInLayout();
            requestLayout();

            // if (mAttached)
            // {
            // this.post(changeTotalRun);
            // } else
            // {
            // mHandler.post(changeTotalRun);
            // }
        }
    }

    // /**
    // * @Description 用于数据变化时重新设置滚动条位置<br/>
    // * @date 2016-3-3
    // */
    // private void resetScrollBarPosition()
    // {
    // if (scrollBarFocus && scrollBarView != null)
    // {
    // scrollBarView.getScrollBarView().setFocusable(true);
    // }
    // mSlideFocusView.getFocusView().setVisibility(View.VISIBLE);
    //
    // if (scrollBarView != null)
    // {
    // int itemH = getChildAt(0).getHeight();
    // int col = getFirstPosition() / getColmusNum();
    // int value = col * itemH;
    // int scrollHeight = scrollBarView.getScrollBarHeight()
    // - scrollBarView.getScrollBarView().getHeight();
    //
    // int temp = MetroHListView.this.getHeight() / getChildAt(0).getHeight();
    //
    // int gridTotalHeight = getCol(mAdapter.getCount()) * getChildAt(0).getHeight()
    // - (temp * getChildAt(0).getHeight());
    // int scrollPostion = 0;
    // if (gridTotalHeight > 0)
    // {
    // if (scrollBarView.getVisibility() != View.VISIBLE)
    // scrollBarView.setVisibility(View.VISIBLE);
    // scrollPostion = (int) ((float) (value * scrollHeight) / gridTotalHeight - 0.5f);
    // if (!scrollBarView.hasFocused())
    // {
    // scrollBarView.setScrollBarToPosition(scrollPostion);
    // } else
    // {
    // scrollBarView.setScrollBar_focusViewPosition(scrollPostion);
    // }
    // isOnePage = false;
    // } else if (gridTotalHeight <= 0)
    // {
    // if (scrollBarView.getVisibility() == View.VISIBLE)
    // scrollBarView.setVisibility(View.GONE);
    // isOnePage = true;
    // }
    // }
    // }

    // Runnable changeTotalRun = new Runnable()
    // {
    // @Override
    // public void run()
    // {
    // final View view = MetroHListView.this.findViewById(curSelectPosition);
    // if (view != null && !view.hasFocus())
    // {
    // view.postDelayed(new Runnable()
    // {
    // @Override
    // public void run()
    // {
    // if (scrollBarView != null && !scrollBarView.hasFocused())
    // {
    // if (mSlideFocusView != null)
    // {
    // mSlideFocusView.stopAnimationOnce();
    // // mSlideFocusView.moveFocusTo(view, null);
    // }
    // view.requestFocus();
    // }
    //
    // resetScrollBarPosition();
    // }
    // }, 300);
    // } else if (view == null)
    // {
    // if (MetroHListView.this.getChildAt(0) != null)
    // {
    // MetroHListView.this.getChildAt(0).post(new Runnable()
    // {
    // @Override
    // public void run()
    // {
    // resetScrollBarPosition();
    // }
    // });
    // }
    // }
    // }
    // };

    @Override
    public void onChanagedAll()
    {
        if (mAdapter != null)
        {
            mListLeft = 0;
            mListLeftOffset = 0;
            mListLeftStart = 0;
            mFirstItemPosition = 0;
            mLastItemPosition = -1;
            mCachedItemViews.clear();
            // if (scrollBarView != null)
            // scrollBarView.setVisibility(View.GONE);
            mRecycleBin.clear();
            removeAllViewsInLayout();
            requestLayout();

            // this.post(new Runnable()
            // {
            // @Override
            // public void run()
            // {
            // getChildAt(0).post(new Runnable()
            // {
            // @Override
            // public void run()
            // {
            // if (scrollBarView != null)
            // {
            // int temp = MetroHListView.this.getHeight()
            // / getChildAt(0).getHeight();
            //
            // int gridTotalHeight = getCol(mAdapter.getCount())
            // * getChildAt(0).getHeight()
            // - (temp * getChildAt(0).getHeight());
            // if (gridTotalHeight > 0)
            // {
            // if (scrollBarView.getVisibility() != View.VISIBLE)
            // scrollBarView.setVisibility(View.VISIBLE);
            // scrollBarView.setScrollBarToPosition(0);
            // isOnePage = false;
            // } else if (gridTotalHeight <= 0)
            // {
            // if (scrollBarView.getVisibility() == View.VISIBLE)
            // scrollBarView.setVisibility(View.GONE);
            // isOnePage = true;
            // }
            // }
            // }
            // });
            // }
            // });
        }
    }

    /**
     * @Description 设置单行滚动时间<br/>
     * @param duration
     *            void
     * @date 2016-1-5
     */
    public void setScrollDuration(int duration)
    {
        this.duration = duration;
        SCROLL_DURING = duration;
    }

    // 调用此方法滚动到目标位置
    public void smoothScrollTo(int fx, int fy)
    {
        if (fx == 0)
        {
            return;
        }
        mListLeftStart = getChildAt(0).getLeft() - mListLeftOffset;
        smoothScrollBy(fx, fy);
        // 改变当前记录的ListView顶部位置
    }

    /**
     * @Description 获取当前List中第一个View的position<br/>
     * @return int
     * @date 2016-1-6
     */
    public int getFirstPosition()
    {
        return getFirstVisibleView() != null ? getFirstVisibleView().getId() : mFirstItemPosition;
    }

    /**
     * @Description 获取当前list中第一个可见的View<br/>
     * @return View
     * @date 2016-1-6
     */
    public View getFirstVisibleView()
    {
        int count = this.getChildCount();
        for (int i = 0; i < count; i++)
        {
            View view = this.getChildAt(i);
            if (view.getLeft() == 0)
            {
                return view;
            }
        }
        return null;
    }

    @Override
    public View getSelectedView()
    {
        return this.getFocusedChild();
    }

    @Override
    public int getSelectedItemPosition()
    {
        return curSelectPosition;
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.widget.AdapterView#setSelection(int) 主要用于强制设置选中位置，即落焦位置
     */
    @Override
    public void setSelection(int position)
    {
        if (position > mAdapter.getCount() - 1 || position < 0)
        {
            throw new UnsupportedOperationException("outOfBounds  position = " + position);
        }
        int tempPostion = position - curSelectPosition;
        int moveCol = Math.abs(position - getFirstPosition());
        View view = this.findViewById(position);
        if (view != null)
        {
            // 滚动
            int scrollSize = 0;
            if (tempPostion > 0)
            {
                if (view.getBottom() > MetroHListView.this.getHeight())
                {
                    scrollSize = -getChildAt(0).getWidth();// * moveCol;
                    key = KeyEvent.KEYCODE_DPAD_DOWN;
                } else
                {
                    if (!view.hasFocus())
                        view.requestFocus();
                    curSelectPosition = position;
                    if (mListener != null)
                        mListener.onHItemSelected(this, view, position);
                }

            } else if (tempPostion < 0)
            {
                if (view.getLeft() < 0)
                {
                    scrollSize = getChildAt(0).getWidth();// * moveCol;
                    key = KeyEvent.KEYCODE_DPAD_UP;
                } else
                {
                    if (!view.hasFocus())
                        view.requestFocus();
                    curSelectPosition = position;
                    if (mListener != null)
                        mListener.onHItemSelected(this, view, position);
                }
            } else
            {
                if (!view.hasFocus())
                    view.requestFocus();
                curSelectPosition = position;
                if (mListener != null)
                    mListener.onHItemSelected(this, view, position);
                return;
            }
            if (moveCol != 0)
                SCROLL_DURING = duration * moveCol;
            curSelectPosition = position;
            if (mSlideFocusView != null)
                mSlideFocusView.stopAnimationOnce();
            smoothScrollTo(scrollSize, 0);
        } else
        {
            int scrollSize = 0;
            if (tempPostion > 0)
            {
                scrollSize = -getChildAt(0).getWidth() * moveCol;
                key = KeyEvent.KEYCODE_DPAD_DOWN;
            } else if (tempPostion < 0)
            {
                scrollSize = getChildAt(0).getWidth() * moveCol;
                key = KeyEvent.KEYCODE_DPAD_UP;
            } else
            {
                return;
            }
            if (moveCol != 0)
                SCROLL_DURING = duration * moveCol;
            curSelectPosition = position;
            if (mSlideFocusView != null)
                mSlideFocusView.stopAnimationOnce();
            smoothScrollTo(scrollSize, 0);
        }
    }

    // /**
    // * @return the clomusNum 当前ListView的列数
    // */
    // public int getColmusNum()
    // {
    // return colmusNum;
    // }

    // /**
    // * @param clomusNum
    // * 设置ListView显示的列数
    // */
    // public void setColmusNum(int colmusNum)
    // {
    // this.colmusNum = colmusNum;
    // }

    // /**
    // * @param scrollBarBgView
    // * 设置滚动条
    // */
    // public void setScrollBarView(MetroListViewScrollBar scrollBarView)
    // {
    // this.scrollBarView = scrollBarView;
    // scrollBarView.setVisibility(View.GONE);
    // if (scrollBarView.getScrollBarFocusBle())
    // {
    // scrollBarView.getScrollBarView().setOnKeyListener(scrollBarKeyListener);
    // } else
    // {
    // setScrollBarVisibleState(true);
    // mHandler.sendEmptyMessageDelayed(SCROLL_STATE, 2000);
    // }
    // }

    /**
     * @Description 判断当前position是否处于最后一行<br/>
     * @param position
     * @return boolean
     * @date 2015-12-8
     */
    public boolean isLastCol(int position)
    {
        // int current = getCol(position + 1);
        // int total = getCol(getAdapter().getCount());
        // if (current == total)
        // return true;
        // return false;

        if (position == getAdapter().getCount() - 1)
            return true;
        return false;
    }

    // /**
    // * @Description 获取当前位置所在行数<br/>
    // * @param pos
    // * @return int
    // * @date 2015-12-8
    // */
    // public int getCol(int pos)
    // {
    // int temp = pos / getColmusNum();
    // int mode = pos % getColmusNum();
    // if (mode != 0)
    // {
    // temp++;
    // }
    // return temp;
    // }

    // 调用此方法设置滚动的相对偏移
    private void smoothScrollBy(int dx, int dy)
    {
        final ValueAnimator transAnim = ValueAnimator.ofFloat(0, dx);
        transAnim.setInterpolator(new DecelerateInterpolator());
        transAnim.setDuration(SCROLL_DURING);
        transAnim.start();
        scrollState = true;
        transAnim.addListener(new AnimatorListenerAdapter()
        {
            @Override
            public void onAnimationEnd(Animator animation)
            {
                super.onAnimationEnd(animation);
                // Log.v("lgx", "isOnKeyUp == " + isOnKeyUp);
                if (mHandler.hasMessages(ON_SCROLL_END))
                    mHandler.removeMessages(ON_SCROLL_END);
                mHandler.sendEmptyMessageDelayed(ON_SCROLL_END, 100);

                View curFocusView = MetroHListView.this.getFocusedChild();
                if (mHandler.hasMessages(key))
                    mHandler.removeMessages(key);
                Message msg = mHandler.obtainMessage(key);
                msg.obj = curFocusView;
                // mHandler.sendMessageDelayed(msg, 100);
                mHandler.sendMessage(msg);

                // if (scrollBarView != null)
                // scrollBarView.setDefaultLastPosition();

                scrollState = false;
                transAnim.cancel();
                transAnim.removeAllListeners();
            }
        });
        transAnim.addUpdateListener(new AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                float value = (Float) animation.getAnimatedValue();
                mListLeft = (int) (mListLeftStart + value);// mScroller.getCurrY();
                // setScrollBarPosition(-value);
                requestLayout();
            }
        });
    }

    // private void setScrollBarPosition(float value)
    // {
    // if (scrollBarView != null && getChildAt(0) != null)
    // {
    // int scrollHeight = scrollBarView.getScrollBarHeight()
    // - scrollBarView.getScrollBarView().getHeight();
    // if (getChildAt(0) == null)
    // return;
    // int temp = this.getHeight() / getChildAt(0).getHeight();
    //
    // int gridTotalHeight = getCol(mAdapter.getCount()) * getChildAt(0).getHeight()
    // - (temp * getChildAt(0).getHeight());
    // int scrollPostion = (int) ((value * scrollHeight) / gridTotalHeight);
    // scrollBarView.setScrollBarPosition(scrollPostion);
    // }
    // }

    /**
     * 静态内部类的实例不会隐式持有他们外部类的引用。
     */
    private static class MyHandler extends Handler
    {
        private final WeakReference<MetroHListView> mLayout;

        public MyHandler(MetroHListView layout)
        {
            mLayout = new WeakReference<MetroHListView>(layout);
        }

        @Override
        public void handleMessage(Message msg)
        {
            MetroHListView layout = mLayout.get();
            if (layout != null)
            {
                int what = msg.what;
                View curFocusView = (View) msg.obj;
                if (what == KeyEvent.KEYCODE_DPAD_LEFT)
                {
                    layout.onKeyLeftFocused(curFocusView);
                    return;
                } else if (what == KeyEvent.KEYCODE_DPAD_RIGHT)
                {
                    layout.onKeyRightFocused(curFocusView);
                    return;
                } else if (what == SCROLL_STATE)
                {
                    // layout.setScrollBarVisibleState(false);
                } else if (what == ON_SCROLL_END)
                {
                    Log.v("lgx", "isOnKeyUp == " + layout.isOnKeyUp);
                    if (layout.scrollListener != null && layout.isOnKeyUp)
                        layout.scrollListener.onHScrollEnd(layout, layout.mFirstItemPosition,
                                layout.mLastItemPosition);
                    if (layout.isOnKeyUp)
                        for (int i = 0; i < layout.getChildCount(); i++)
                        {
                            ((MetroListItem) layout.getChildAt(i)).refreshView();
                        }
                }
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);

        if (mAdapter == null)
        {
            return;
        }

        if (this.getChildCount() == 0)// 填满第一屏，第一次初始化数据UI时使用
        {
            fillListRight(mListLeft, 0);
            if (this.getChildCount() != 0)
            {
                int temp = this.getWidth() / getChildAt(0).getMeasuredWidth();
                if (temp >= 4)
                {
                    duration = 100;
                    SCROLL_DURING = duration;
                }
                for (int i = 0; i < this.getChildCount(); i++)
                {
                    ((MetroListItem) getChildAt(i)).refreshView();
                }
            }
        } else
        // 当翻页滚动时触发,回收复用，已经位置刷新
        {
            final int offset = mListLeft + mListLeftOffset - getChildAt(0).getLeft();
            // 移除可视区域的都干掉
            removeNonVisibleViews(offset);

            fillList(offset);
        }

        // layout，添加测量完后，获取视图摆放位置
        positioinItems();

        // draw， 上面子视图都添加完了，重绘布局把子视图绘制出来吧
        invalidate();
    }

    /**
     * ListView向上或者向下移动后需要向顶部或者底部添加视图
     * 
     * @param offset
     */
    private void fillList(final int offset)
    {
        // 最后一个item的下边界值就是当前ListView的下边界值
        final int bottomEdge = getChildAt(getChildCount() - 1).getRight();
        fillListRight(bottomEdge, offset);

        // 第一个Item的上边界值就是ListVie的上边界值
        final int leftEdge = getChildAt(0).getLeft();
        fillListLeft(leftEdge, offset);
    }

    /**
     * 与fillListDown相反方向添加
     * 
     * @param topEdge
     *            当前第一个子视图顶部边界值
     * @param offset
     *            显示区域偏移量
     */
    private void fillListLeft(int leftEdge, int offset)
    {
        while (leftEdge + offset > 0 && mFirstItemPosition > 0)
        {
            // 现在添加的视图时当前子视图前面，所以位置-1
            mFirstItemPosition--;

            View newTopChild = mAdapter.getView(mFirstItemPosition,
                    getCachedView(mFirstItemPosition), this);
            newTopChild.setOnKeyListener(this);
            newTopChild.setOnClickListener(this);
            newTopChild.setId(mFirstItemPosition);
            addAndMeasureChild(newTopChild, LAYOUT_MODE_ABOVE);
            int childWidth = newTopChild.getMeasuredWidth();

            leftEdge -= childWidth;
            // 在顶部添加视图后，更新顶部偏移
            mListLeftOffset -= childWidth;// - verticalSpace;
        }
    }

    /**
     * 向当前最后一个子视图下面添加，填充到当前ListView底部无再可填充区域为止
     * 
     * @param bottomEdge
     *            当前最后一个子视图底部边界值
     * @param offset
     *            显示区域偏移量
     */
    private void fillListRight(int rightEdge, int offset)
    {
        while (rightEdge + offset < getWidth() && mLastItemPosition < mAdapter.getCount() - 1)
        {
            // 现在添加的视图时当前子视图后面，所以位置+1
            mLastItemPosition++;

            // 数据和视图通过Adapter适配，此处从Adapter获取视图。
            // 第二个参数传入复用的View对象，先出入null，之后再添加View对象复用机制
            View newBottomChild = mAdapter.getView(mLastItemPosition,
                    getCachedView(mLastItemPosition), this);
            newBottomChild.setOnKeyListener(this);
            newBottomChild.setOnClickListener(this);
            newBottomChild.setId(mLastItemPosition);
            // **具体添加视图处理
            addAndMeasureChild(newBottomChild, LAYOUT_MODE_BELOW);
            // 添加一个子视图(Item)，随之底部边界也发生改变
            rightEdge += newBottomChild.getMeasuredWidth();
        }
    }

    /**
     * 向当前ListView添加子视图并负责Measure子视图操作
     * 
     * @param child
     *            需要添加的ListView子视图(Item)
     * @param layoutMode
     *            在顶部添加上面添加还是在底部下面添加子视图 ， LAYOUT_MODE_ABOVE 或 LAYOUT_MODE_BELOW
     */
    private void addAndMeasureChild(View child, int layoutMode)
    {
        LayoutParams params = child.getLayoutParams();
        if (params == null)
        {
            params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        }

        final int index = layoutMode == LAYOUT_MODE_ABOVE ? 0 : -1;
        addViewInLayout(child, index, params, true);

        child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
    }

    /**
     * 对所有子视图进行layout操作，取得所有子视图正确的位置
     */
    private void positioinItems()
    {
        int left = mListLeft + mListLeftOffset;
        int top = 0;
        for (int i = 0; i < getChildCount(); i++)
        {
            final View child = getChildAt(i);

            // 当前视图未虽然添加到ViewGroup但是还未重新进行measure, layout, draw操作
            // 直接通过child.getWidth();获取不到宽度
            final int width = child.getMeasuredWidth();
            final int height = child.getMeasuredHeight();

            child.layout(left, top, left + width, top + height);
            left += width;
        }
    }

    // /**
    // * @Fields scrollBarKeyListener 滚动条按键监听
    // */
    // OnKeyListener scrollBarKeyListener = new OnKeyListener()
    // {
    // @Override
    // public boolean onKey(View v, int keyCode, KeyEvent event)
    // {
    // if (event.getAction() == KeyEvent.ACTION_UP)
    // {
    // isOnKeyUp = true;
    // }
    // if (event.getAction() == KeyEvent.ACTION_DOWN)
    // {
    // if (scrollState)
    // {
    // return true;
    // }
    // int firstPosition = getFirstPosition();
    // if (getChildAt(0) == null)
    // return true;
    // int pageRow = MetroHListView.this.getHeight() / getChildAt(0).getHeight();
    // isOnKeyUp = false;
    // switch (keyCode)
    // {
    // case KeyEvent.KEYCODE_DPAD_UP:
    // if (firstPosition < colmusNum)
    // {
    // isOnKeyUp = true;
    // return true;
    // } else
    // {
    // if (firstPosition - pageRow * colmusNum < 0)
    // {
    // int tempRow = getFirstPosition() / colmusNum;
    // smoothScrollTo(0, tempRow * getChildAt(0).getHeight());
    // } else
    // {
    // smoothScrollTo(0, pageRow * getChildAt(0).getHeight());
    // }
    // return true;
    // }
    //
    // case KeyEvent.KEYCODE_DPAD_DOWN:
    // if (firstPosition + pageRow * colmusNum * 2 > mAdapter.getCount() - 1)
    // {
    // isOnKeyUp = true;
    // int targetPostion = (mAdapter.getCount() - 1)
    // - ((mAdapter.getCount() - 1) % colmusNum);
    // smoothScrollTo(0, -((targetPostion - firstPosition) / colmusNum
    // - pageRow + 1)
    // * getChildAt(0).getHeight());
    // } else
    // {
    // smoothScrollTo(0, -pageRow * getChildAt(0).getHeight());
    // }
    // return true;
    //
    // case KeyEvent.KEYCODE_DPAD_LEFT:
    // int targetPosition = getFirstPosition() + colmusNum - 1;
    // if (targetPosition > mAdapter.getCount() - 1)
    // {
    // targetPosition = mAdapter.getCount() - 1;
    // }
    // View view = MetroHListView.this.findViewById(targetPosition);
    // if (view != null)
    // {
    // view.requestFocus();
    // curSelectPosition = targetPosition;
    // if (mListener != null)
    // mListener.onItemSelected(MetroHListView.this, view, targetPosition);
    // if (mBarOnKeyListener != null)
    // mBarOnKeyListener.onScrollBarOnKey(v, keyCode);
    // // if (mSlideFocusView != null)
    // // mSlideFocusView.changeFocusBg(R.drawable.ui_sdk_btn_focuse_no_bg);
    // return true;
    // }
    // return mBarOnKeyListener != null ? mBarOnKeyListener.onScrollBarOnKey(v,
    // keyCode) : false;
    //
    // case KeyEvent.KEYCODE_DPAD_RIGHT:
    // return mBarOnKeyListener != null ? mBarOnKeyListener.onScrollBarOnKey(v,
    // keyCode) : false;
    //
    // default:
    // if (itemOnKeyListener != null)
    // return itemOnKeyListener.onItemOnKeyEvent(v, keyCode, v.getId());
    // break;
    // }
    // }
    // return false;
    // }
    // };

    // private void setScrollBarVisibleState(final boolean show)
    // {
    // if (isOnePage)
    // {
    // return;
    // }
    // AlphaAnimation alphaAnimation = null;
    // if (show)
    // {
    // alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
    // alphaAnimation.setDuration(100);
    // alphaAnimation.setFillAfter(true);
    // } else
    // {
    // alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
    // alphaAnimation.setDuration(100);
    // alphaAnimation.setFillAfter(true);
    // }
    // alphaAnimation.setAnimationListener(new AnimationListener()
    // {
    //
    // @Override
    // public void onAnimationStart(Animation animation)
    // {
    // }
    //
    // @Override
    // public void onAnimationRepeat(Animation animation)
    // {
    // }
    //
    // @Override
    // public void onAnimationEnd(Animation animation)
    // {
    // if (show)
    // {
    // scrollBarView.setVisibility(View.VISIBLE);
    // } else
    // {
    // scrollBarView.setVisibility(View.INVISIBLE);
    // }
    // scrollBarView.clearAnimation();
    // }
    // });
    // scrollBarView.startAnimation(alphaAnimation);
    // }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event)
    {
        int action = event.getAction();
        if (action == KeyEvent.ACTION_UP)
        {
            isOnKeyUp = true;
        }
        if (action == KeyEvent.ACTION_DOWN)
        {
            if (scrollState)
            {
                return true;
            }
            // if (scrollBarView != null && !scrollBarView.getScrollBarFocusBle())
            // {
            // if (mHandler.hasMessages(SCROLL_STATE))
            // mHandler.removeMessages(SCROLL_STATE);
            // if (scrollBarView.getVisibility() != View.VISIBLE)
            // setScrollBarVisibleState(true);
            // mHandler.sendEmptyMessageDelayed(SCROLL_STATE, 2000);
            // }
            key = keyCode;
            int curPosition = v.getId();
            int focusId = getFocusedChild().getId();
            switch (keyCode)
            {
                case KeyEvent.KEYCODE_DPAD_UP:
                    if (itemOnKeyListener != null)
                        return itemOnKeyListener.onHBorderItemOnKeyEvent(v, keyCode, curPosition);
                    return false;

                case KeyEvent.KEYCODE_DPAD_DOWN:
                    if (itemOnKeyListener != null)
                        return itemOnKeyListener.onHBorderItemOnKeyEvent(v, keyCode, curPosition);
                    return false;

                case KeyEvent.KEYCODE_DPAD_LEFT:
                    isOnKeyUp = false;
                    long upTime = System.currentTimeMillis();
                    if ((upTime - onKeyTime) < 110)
                    {
                        // if (duration > 200)
                        // SCROLL_DURING = duration / 2;
                        // else
                        // SCROLL_DURING = duration;
                        SCROLL_DURING = duration;
                    } else
                    {
                        SCROLL_DURING = duration;
                    }
                    onKeyTime = System.currentTimeMillis();

                    int left = v.getLeft();
                    if (left == 0 && curPosition > 0)
                    {
                        if (mSlideFocusView != null)
                            mSlideFocusView.stopAnimationOnce();
                        smoothScrollTo(getChildAt(0).getWidth(), 0);
                        if (curPosition == 1)
                            isOnKeyUp = true;
                    } else
                    {
                        onKeyLeftFocused(v);
                        if (curPosition == 0)
                        {
                            isOnKeyUp = true;
                            if (itemOnKeyListener != null)
                                return itemOnKeyListener.onHBorderItemOnKeyEvent(v, keyCode,
                                        curPosition);
                        }
                    }
                    return true;

                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    isOnKeyUp = false;
                    long downTime = System.currentTimeMillis();
                    if ((downTime - onKeyTime) < 110)
                    {
                        // if (duration > 200)
                        // SCROLL_DURING = duration / 2;
                        // else
                        // SCROLL_DURING = duration;
                        SCROLL_DURING = duration;
                    } else
                    {
                        SCROLL_DURING = duration;
                    }
                    onKeyTime = System.currentTimeMillis();

                    int right = v.getRight();
                    if ((right + v.getWidth()) - v.getPaddingLeft() * 2 > MetroHListView.this
                            .getWidth() && !isLastCol(curPosition))
                    {
                        if (mSlideFocusView != null)
                            mSlideFocusView.stopAnimationOnce();
                        smoothScrollTo(-getChildAt(0).getWidth(), 0);

                        if (curPosition == mAdapter.getCount() - 2)
                            isOnKeyUp = true;
                    } else
                    {
                        if (!isLastCol(curPosition))
                        {
                            onKeyRightFocused(v);
                        } else
                        {
                            isOnKeyUp = true;
                            return true;
                        }
                    }
                    return true;

                default:
                    if (itemOnKeyListener != null)
                        return itemOnKeyListener.onHItemOnKeyEvent(v, keyCode, curPosition);
                    break;
            }
        }
        return false;
    }

    /**
     * @Description 遥控上键焦点处理处理
     * @param curFocusView
     *            void
     * @date 2015-12-24
     */
    private boolean onKeyLeftFocused(View curFocusView)
    {
        if (curFocusView == null)
        {
            return false;
        }

        int nextFocusId = curFocusView.getId() - 1;
        View nextFocusView;
        if (nextFocusId >= 0)
        {
            for (int i = 0; i < MetroHListView.this.getChildCount(); i++)
            {
                if (MetroHListView.this.getChildAt(i) != null
                        && MetroHListView.this.getChildAt(i).getId() == nextFocusId)
                {
                    nextFocusView = MetroHListView.this.getChildAt(i);
                    nextFocusView.requestFocus();
                    if (mListener != null)
                    {
                        curSelectPosition = nextFocusId;
                        mListener.onHItemSelected(MetroHListView.this, nextFocusView, nextFocusId);
                        mListener.onHItemUnSelected(MetroHListView.this, curFocusView);
                    }
                    break;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * @Description 遥控下键焦点处理处理
     * @param curFocusView
     *            void
     * @date 2015-12-24
     */
    private void onKeyRightFocused(View curFocusView)
    {
        if (curFocusView == null)
        {
            return;
        }

        int nextFocusId = curFocusView.getId() + 1;
        View nextFocusView;
        if (nextFocusId > mAdapter.getCount() - 1)
        {
            nextFocusId = mAdapter.getCount() - 1;
        }
        for (int i = 0; i < MetroHListView.this.getChildCount(); i++)
        {
            if (MetroHListView.this.getChildAt(i) != null
                    && MetroHListView.this.getChildAt(i).getId() == nextFocusId)
            {
                nextFocusView = MetroHListView.this.getChildAt(i);
                nextFocusView.requestFocus();
                if (mListener != null)
                {
                    curSelectPosition = nextFocusId;
                    mListener.onHItemSelected(MetroHListView.this, nextFocusView, nextFocusId);
                    mListener.onHItemUnSelected(MetroHListView.this, curFocusView);
                }
                break;
            }
        }
    }

    /**
     * 删除当前已经移除可视范围的Item View <br/>
     * 主要用于 子Item的回收和复用，已结束内存消耗，以及UI的顺畅
     * 
     * @param offset
     *            可视区域偏移量
     */
    private void removeNonVisibleViews(final int offset)
    {
        int childCount = getChildCount();

        /** ListView向上滚动，删除顶部移除可视区域的所有视图 **/

        // 不在ListView底部，子视图大于1
        if (mLastItemPosition != mAdapter.getCount() - 1 && childCount > 1)
        {
            View firstChild = getChildAt(0);
            // 通过第二条件判断当前最上面的视图是否被移除可是区域
            while (firstChild != null && firstChild.getRight() + offset < 0)
            {
                // 既然顶部第一个视图已经移除可视区域从当前ViewGroup中删除掉
                removeViewInLayout(firstChild);
                firstChild.setOnKeyListener(null);
                firstChild.setOnClickListener(null);
                // 用于下次判断，是否当前顶部还有需要移除的视图
                childCount--;
                // View对象回收，目的是为了复用
                mCachedItemViews.addLast(firstChild);
                mRecycleBin.addScrapView(((MetroListItem) firstChild).mViewType, firstChild);
                // 既然最上面的视图被干掉了，当前ListView第一个显示视图也需要+1
                mFirstItemPosition++;
                // 同上更新
                mListLeftOffset += firstChild.getMeasuredWidth();
                // 为下一次while遍历获取参数
                if (childCount > 1)
                {
                    // 当前已经删除第一个，再接着去除删除后剩余的第一个
                    firstChild = getChildAt(0);
                } else
                {
                    // 没啦
                    firstChild = null;
                }
            }
        }

        /** ListView向下滚动，删除底部移除可视区域的所有视图 **/
        // 与上面操作一样，只是方向相反一个顶部操作一个底部操作
        if (mFirstItemPosition != 0 && childCount > 1)
        {
            View lastChild = getChildAt(childCount - 1);
            while (lastChild != null && lastChild.getLeft() + offset > getWidth())
            {
                removeViewInLayout(lastChild);
                lastChild.setOnKeyListener(null);
                lastChild.setOnClickListener(null);
                childCount--;
                mCachedItemViews.addLast(lastChild);
                mRecycleBin.addScrapView(((MetroListItem) lastChild).mViewType, lastChild);
                mLastItemPosition--;

                if (childCount > 1)
                {
                    lastChild = getChildAt(childCount - 1);
                } else
                {
                    lastChild = null;
                }
            }
        }

    }

    /**
     * 获取一个可以复用的Item View
     * 
     * @return view 可以复用的视图或者null
     */
    private View getCachedView(int position)
    {

        return mRecycleBin.getScrapView(position);
        // if (mCachedItemViews.size() != 0)
        // {
        // return mCachedItemViews.removeFirst();
        // }
        //
        // return null;
    }

    @Override
    public void onClick(View v)
    {
        if (mItemClickListener != null)
            mItemClickListener.onItemClick(this, v, v.getId(), v.getId());
    }

    public class RecycleBin
    {
        private int mViewTypeCount;
        private LinkedList<View>[] mCachedItemViews;
        private LinkedList<View> mCurrentScrap;

        @SuppressWarnings("unchecked")
        public void setViewTypeCount(int viewTypeCount)
        {
            if (viewTypeCount < 1)
            {
                throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
            }
            mCachedItemViews = new LinkedList[viewTypeCount];
            for (int i = 0; i < viewTypeCount; i++)
            {
                mCachedItemViews[i] = new LinkedList<View>();
            }
            mCurrentScrap = mCachedItemViews[0];
            mViewTypeCount = viewTypeCount;
        }

        public void clear()
        {
            if (mViewTypeCount == 1)
            {
                mCurrentScrap.clear();
            } else
            {
                final int typeCount = mViewTypeCount;
                for (int i = 0; i < typeCount; i++)
                {
                    mCachedItemViews[i].clear();
                }
            }
        }

        public void addScrapView(Integer type, View view)
        {
            if (mViewTypeCount == 1)
            {
                mCurrentScrap.add(view);
            } else
            {
                mCachedItemViews[type].add(view);
            }
        }

        public View getScrapView(int position)
        {
            if (mViewTypeCount == 1)
            {
                if (mCurrentScrap.size() != 0)
                    return mCurrentScrap.removeFirst();
            } else
            {
                int whichScrap = mAdapter.getItemViewType(position);
                if (whichScrap >= 0 && whichScrap < mCachedItemViews.length
                        && mCachedItemViews[whichScrap].size() > 0)
                {
                    return mCachedItemViews[whichScrap].removeFirst();
                }
            }
            return null;
        }

    }

}
